﻿using System;
using System.Diagnostics;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;

using xEngine.Input;
using xEngine.Debugging;
using xEngine.Rendering;
using xEngine.Utils;

namespace xEngine.UI
{
    public abstract class XWindow : Game, XRenderer
    {
        #region Member Variables

        private InputManager _input;
        private ScreenManager _screenManager;

        #endregion

        #region Properties

        public static string EngineVersion
        {
            get
            {
                FileVersionInfo fvi = FileVersionInfo.GetVersionInfo("xengine.dll");
                return fvi.FileMajorPart + "." + fvi.FileMinorPart + "." + fvi.FileBuildPart;
            }
        }
        
        protected GraphicsDeviceManager Graphics { get; private set; }
        protected InputManager Input { get { return _input; } }

        protected ScreenManager ScreenManager { get { return _screenManager; } }

        public bool ShowConsole { get; protected set; }

        public SpriteBatch SpriteBatch { get; private set; }

        public bool ShowOSD { get; protected set; }
        protected Color OSDColor { get; set; }
        protected SpriteFont OSDFont { get; set; }

        protected bool ProcessMouse { get; set; }
        protected bool ProcessKeyboard { get; set; }

        #endregion

        #region Constructors

        public XWindow()
        {
            Graphics = new GraphicsDeviceManager(this);
            Graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(OnPreparingDeviceSettings);
            Content = new XContentManager(Services);

            RenderManager.Initialize(this);
            DataLoader.Initialize(this);
            XConsole.Owner = this;
            XConsole.MaxEntries = 1000;

            ProcessKeyboard = ProcessMouse = true;
        }

        #endregion
        
        #region Initialization

        protected override void Initialize()
        {
            // Input System
            _input = new InputManager(new Point(Graphics.PreferredBackBufferWidth / 2, Graphics.PreferredBackBufferHeight / 2));
            _input.MouseMoved += new EventHandler<MouseMovedEventArgs>(OnMouseMoved);
            _input.MouseWheel += new EventHandler<MouseWheelEventArgs>(OnMouseWheel);
            _input.MouseDown += new EventHandler<MouseButtonEventArgs>(OnMouseDown);
            _input.MouseUp += new EventHandler<MouseButtonEventArgs>(OnMouseUp);
            _input.KeyDown += new EventHandler<KeyEventArgs>(OnKeyDown);

            _input.AddKeyEventHandler(Keys.Enter, KeyModifier.Alt, delegate(object s, KeyDefinitionEventArgs e) {
                Graphics.ToggleFullScreen();
                e.ApplyLock = true;
            });

            GenericResources.Initialize(GraphicsDevice);
            XConsole.Font = GenericResources.Fonts.Fixed08;

            _screenManager = new ScreenManager(this);
            Components.Add(_screenManager);

            base.Initialize();
        }

        protected override void LoadContent()
        {
            SpriteBatch = new SpriteBatch(GraphicsDevice);
            OSDColor = Color.White;
            OSDFont = Rendering.RenderManager.EmbeddedContent.Load<SpriteFont>("f_osd");
        }
        protected override void BeginRun()
        {
            base.BeginRun();
            VideoSettingsChanged();            
        }
        
        protected virtual void VideoSettingsChanged()
        {
            Graphics.ApplyChanges();
            ScreenManager.VideoSettingsChanged();
            XConsole.VideoSettingsChanged();
        }
        protected void OnPreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
        {
            e.GraphicsDeviceInformation.PresentationParameters.RenderTargetUsage = RenderTargetUsage.PreserveContents;
        }

        #endregion

        #region Dispose

        protected override void UnloadContent()
        {
            _screenManager.Dispose();
            SpriteBatch.Dispose();
        }

        #endregion

        #region Functions

        protected virtual void OnKeyDown(object sender, KeyEventArgs e)
        {
            if (ShowConsole)
                XConsole.OnKeyPress(e);
        }
        protected virtual void OnMouseDown(object sender, MouseButtonEventArgs e) { }
        protected virtual void OnMouseUp(object sender, MouseButtonEventArgs e) { }
        protected virtual void OnMouseMoved(object sender, MouseMovedEventArgs e) { }
        protected virtual void OnMouseWheel(object sender, MouseWheelEventArgs e) { }

        public virtual bool ProcessConsoleCommand(string cmd, params string[] param)
        {
            bool processed = true;

            switch (cmd)
            {
                case "clear":
                case "cls":
                    XConsole.Clear();
                    break;

                case "quit":
                case "exit":
                    Exit();
                    break;

                default:
                    processed = false;
                    break;
            }

            return processed;
        }

        protected override void Update(GameTime gameTime)
        {
            if(ProcessKeyboard)
                _input.ProcessKeyboard();
            
            if(ProcessMouse)
                _input.ProcessMouse();

            if(!ShowConsole)
                base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            Render(gameTime);

            base.Draw(gameTime);

            if (ShowOSD)
                OSD.Render(OSDFont, OSDColor);

            if (ShowConsole)
                XConsole.Render();
        }

        protected abstract void Render(GameTime gameTime);

        #endregion

        #region Enums
        #endregion
    }
}
